use crate::imp::tonicrpc::ekhokcp::kcp_imp::EkhoKcpImp;
use crate::imp::tonicrpc::kcptunnel::tunnel::TunnelConn;
use ekho::kcp::Config;
use std::{pin::Pin, sync::Arc, usize};
use tokio::io::{AsyncRead, AsyncWrite};
pub use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tonic::transport::server::Connected;
use webrtc_ice::agent::Agent;
use webrtc_util::Conn;

/// IAsyncKcpTunnel trait for asnyc read and async write
pub trait IAsyncKcpTunnel: AsyncRead + AsyncWrite + Unpin + Send {}

// tunnel id to kcp conv 32
// tunnel id = (intvalue_randomstring)
pub fn tunnel_id_str_to_conv_u32(id: &str) -> Result<u32, anyhow::Error> {
    let parts: Vec<&str> = id.split("_").collect();
    if parts.len() >= 2 {
        let id: u128 = parts[0].parse()?;
        Ok(id as u32)
    } else {
        anyhow::bail!("id pattern error")
    }
}

pub struct KcpTunnelImp {
    stream: Box<dyn IAsyncKcpTunnel>,

    pub ice_agent: Arc<Agent>,
    pub remote_client_id: String,
    pub local_client_id: String,
    pub tunnel_id: String,
    pub cancel_tx: tokio::sync::mpsc::Sender<()>,
    pub is_controlling: bool,
}

unsafe impl Send for KcpTunnelImp {}
unsafe impl Sync for KcpTunnelImp {}

impl KcpTunnelImp {
    pub fn new(
        stream: Box<dyn IAsyncKcpTunnel>,
        ice_agent: Arc<Agent>,
        remote_client_id: String,
        local_client_id: String,
        tunnel_id: String,
        cancel_tx: tokio::sync::mpsc::Sender<()>,
        is_controlling: bool,
    ) -> Self {
        KcpTunnelImp {
            stream,
            ice_agent,
            remote_client_id,
            local_client_id,
            tunnel_id,
            cancel_tx,
            is_controlling,
        }
    }
}
// implentation for tonic Connected trait.
impl Connected for KcpTunnelImp {
    type ConnectInfo = i64;

    fn connect_info(&self) -> Self::ConnectInfo {
        let conv = tunnel_id_str_to_conv_u32(self.tunnel_id.as_str()).unwrap_or_default();
        log::info!("tonic kcp connect_info conv:{}", conv);
        conv.into()
    }
}

impl std::fmt::Debug for KcpTunnelImp {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("KcpTunnelImp")
            .field("remote_client_id", &self.remote_client_id)
            .field("local_client_id", &self.local_client_id)
            .field("tunnel_id", &self.tunnel_id)
            .field("cancel_tx", &self.cancel_tx)
            .field("is_controlling", &self.cancel_tx)
            .finish()
    }
}

impl AsyncRead for KcpTunnelImp {
    fn poll_read(
        mut self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
        buf: &mut tokio::io::ReadBuf<'_>,
    ) -> std::task::Poll<std::io::Result<()>> {
        Pin::new(&mut self.stream).poll_read(cx, buf)
    }
}
impl AsyncWrite for KcpTunnelImp {
    fn poll_write(
        mut self: Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
        buf: &[u8],
    ) -> std::task::Poll<Result<usize, std::io::Error>> {
        Pin::new(&mut self.stream).poll_write(cx, buf)
    }

    fn poll_flush(
        mut self: Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Result<(), std::io::Error>> {
        Pin::new(&mut self.stream).poll_flush(cx)
    }

    fn poll_shutdown(
        mut self: Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Result<(), std::io::Error>> {
        Pin::new(&mut self.stream).poll_shutdown(cx)
    }
}
